/*----------------------------------------------------------------------
 *
 *  Copyright 2007, Thomas Dejanovic.
 *
 *  This is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation; either version 2.1 of
 *  the License, or (at your option) any later version.
 *
 *  This software is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this software; if not, write to the Free
 *  Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 *  02110-1301 USA, or see the FSF site: http://www.fsf.org.
 *
 *----------------------------------------------------------------------
 *
 *  testbench for test001.
 *
 *----------------------------------------------------------------------
 *  id = $Id: testbench_001.v 667 2010-07-01 00:12:17Z jayshurtz $
 *  $URL: http://hatch.googlecode.com/svn/tags/taggle_release_2.2/test/old_tests/rtl/testbench_001.v $
 *  $Author: jayshurtz $
 *---------------------------------------------------------------------*/

module testbench_001
  ();

  /*----------------------------------------------------------------*/

  initial begin
`ifdef IVERILOG
    $display("*** dumping vcd file for iverilog.");
    $dumpfile("testbench_001.vcd");
    $dumpvars(0);
`else
    $display("*** no dump file will be created.");
`endif
  end

  /*----------------------------------------------------------------*/

  /*AUTOREG*/

  /*AUTOWIRE*/

  /*------------------------------------------------------------------
   *
   * local definitions and connections.
   *
   * */

  // apb interface.
  wire                  pclk;
  wire                  pclk_en;
  wire                  gated_pclk;
  wire                  gated_pclk_en;
  reg                   preset_l;
  reg                   penable;
  reg                   psel;
  reg                   pwrite;
  reg [31:0]            pwdata;
  wire [31:0]           prdata;
  reg [9:2]             paddr;

//`define DEBUG

  `include "apb_bus_tasks.v"

  // register functions in HW
  wire [31:0]           real_time_clock;
  reg [9:0]             test_a_in;
  reg                   test_a_we;
  reg                   test_a_dec;
  reg                   test_a_set;
  reg [9:0]             test_b_in;
  reg                   test_b_we;
  reg                   test_b_dec;
  reg                   test_b_clear;
  reg [9:0]             test_c_in;
  reg                   test_c_we;
  reg                   test_c_dec;
  reg                   test_c_inc;
  reg [9:0]             test_d_in;
  reg                   test_d_we;
  reg                   test_d_clear;
  reg                   test_d_set;
  reg [9:0]             test_e_in;
  reg                   test_e_we;
  reg                   test_e_clear;
  reg [9:0]             test_f_in;
  reg                   test_f_we;
  reg                   test_f_inc;
  reg                   test_f_clear;
  reg                   tick;
  wire                  tick_1ms;
  wire                  tick_16ms;
  wire                  tick_64ms;

  /*------------------------------------------------------------------
   *
   * apb interface.
   *
   * */

  integer    i;
  reg [31:0] d_in, d_out, a, d;
  initial begin
    // wait for reset to be deasserted.
    $display("Waiting for reset to be deasserted.");
    while (preset_l !== 1'd1) begin
      @ (posedge pclk);
    end

    $display("Starting RTC data access test.");

    // read / write a bunch of random numbers to the real time clock
    // register.
    a = 0;
    for (i=0 ; i<500; i=i+1) begin
      d_in = $random;
      apb_write(a, d_in);
      apb_read(a, d_out);
      if ((d_in !== d_out) && (((d_in + 32'd1) & ~32'd0) !== d_out))
        $display("*** ERROR : expected 0x%x but read 0x%x from address 0x%x", d_in, d_out, a);
    end

    a = 0;
    for (i=0 ; i<500; i=i+1) begin
      d_in = $random;
      apb_write(a, d_in);
      apb_read(a, d_out);
      if ((d_in !== d_out) && (((d_in + 32'd1) & ~32'd0) !== d_out))
        $display("*** ERROR : expected 0x%x but read 0x%x from address 0x%x", d_in, d_out, a);
      @ (posedge pclk);
    end

    for (i=0 ; i<500; i=i+1) begin
      d_in = $random;
      apb_write(a, d_in);
      @ (posedge pclk);
      apb_read(a, d_out);
      if ((d_in !== d_out) && (((d_in + 32'd1) & ~32'd0) !== d_out))
        $display("*** ERROR : expected 0x%x but read 0x%x from address 0x%x", d_in, d_out, a);
    end

    for (i=0 ; i<500; i=i+1) begin
      d_in = $random;
      apb_write(a, d_in);
      @ (posedge pclk);
      apb_read(a, d_out);
      if ((d_in !== d_out) && (((d_in + 32'd1) & ~32'd0) !== d_out))
        $display("*** ERROR : expected 0x%x but read 0x%x from address 0x%x", d_in, d_out, a);
      @ (posedge pclk);
    end
    $display("Done RTC data access test.");


    // now test that writing to test registers a sn b does not work as
    // they are not writable.  register c is in the same pack and is
    // in the low order bits.
    $display("Testing access to read only registers.");
    a = 4;
    apb_read(a, d);
    d_in = (d & 30'h3ff) | (~d & ~30'h3ff);
    apb_write(a, d_in);
    apb_read(a, d_out);
    // it should not have changed.
    if (d !== d_out)
      $display("*** ERROR : expected 0x%x but read 0x%x from address 0x%x which should have been partialy read only", d, d_out, a);

    d_in = (d & 30'h3ff) | ((d ^ 30'h15555555) & ~30'h3ff);
    apb_write(a, d_in);
    apb_read(a, d_out);
    // it should not have changed.
    if (d !== d_out)
      $display("*** ERROR : expected 0x%x but read 0x%x from address 0x%x which should have been partialy read only", d, d_out, a);

    // test writing to register c which is in the same pack as a and b.
    $display("Testing access to a read / write register in a pack of read only registers.");
    a = 4;
    apb_read(a, d);
    for (i=0 ; i<5; i=i+1) begin
      d_in = $random & 30'h3ff;
      apb_write(a, d_in);
      apb_read(a, d_out);
      // it should have worked.
      if (d_in !== (d_out & 30'h3ff))
      $display("*** ERROR : expected 0x%x but read 0x%x from address 0x%x", d_in, d_out, a);
    end

    $display("Done.");

    $finish;
  end


  /*------------------------------------------------------------------
   *
   * hw functions.
   *
   * */

  reg [7:0]             tick_counter;
  reg                   tick_d;
  reg                   rtc_write_d;
  reg [31:0]            real_time_clock_d;
  always @ (posedge pclk) begin
    tick_d <= tick;
    rtc_write_d <= psel & penable & (paddr == 7'd0) & pwrite;
    real_time_clock_d <= real_time_clock;
   if (~preset_l) begin
      test_a_in    <= 10'd0;
      test_a_we    <= 1'd0;
      test_a_dec   <= 1'd0;
      test_a_set   <= 1'd0;

      test_b_in    <= 10'd0;
      test_b_we    <= 1'd0;
      test_b_dec   <= 1'd0;
      test_b_clear <= 1'd0;

      test_c_in    <= 10'd0;
      test_c_we    <= 1'd0;
      test_c_dec   <= 1'd0;
      test_c_inc   <= 1'd0;

      test_d_clear <= 1'd0;
      test_d_set   <= 1'd0;

      test_e_clear <= 1'd0;

      test_f_inc   <= 1'd0;
      test_f_clear <= 1'd0;

      tick         <= 1'd0;
      tick_counter <= 8'd0;
    end else begin
      tick <= tick_counter == 8'd0;
      tick_counter <= tick_counter + 8'd1;

      if (tick_d & ~rtc_write_d) begin
        // we got a tick that is not overwriten by the cpu.
        if (((real_time_clock_d + 32'd1) & ~32'd0) !== real_time_clock)
          $display("*** ERROR : RTC counter did not increment as expected at time %t", $time);
        else
          $display("RTC counter incremented as expected.");
      end else if (tick_d & rtc_write_d) begin
          $display("RTC counter increment over written.");
      end
    end
  end


  /*------------------------------------------------------------------
   *
   * instantiations.
   *
   * */


  /* test001_hatch AUTO_TEMPLATE
   (
   .test_a_\(p.*\) (\1[]),
   .test_a_\(gated_p.*\) (\1[]),
   ); */
  test001_hatch test001
    (/*AUTOINST*/
     // Outputs
     .test_a_prdata                     (prdata[31:0]),          // Templated
     .real_time_clock                   (real_time_clock[31:0]),
     // Inputs
     .test_a_pclk                       (pclk),                  // Templated
     .test_a_pclk_en                    (pclk_en),               // Templated
     .test_a_gated_pclk                 (gated_pclk),            // Templated
     .test_a_gated_pclk_en              (gated_pclk_en),         // Templated
     .test_a_preset_l                   (preset_l),              // Templated
     .test_a_penable                    (penable),               // Templated
     .test_a_psel                       (psel),                  // Templated
     .test_a_pwrite                     (pwrite),                // Templated
     .test_a_pwdata                     (pwdata[31:0]),          // Templated
     .test_a_paddr                      (paddr[9:2]),            // Templated
     .test_a_in                         (test_a_in[9:0]),
     .test_a_we                         (test_a_we),
     .test_a_dec                        (test_a_dec),
     .test_a_set                        (test_a_set),
     .test_b_in                         (test_b_in[9:0]),
     .test_b_we                         (test_b_we),
     .test_b_dec                        (test_b_dec),
     .test_b_clear                      (test_b_clear),
     .test_c_in                         (test_c_in[9:0]),
     .test_c_we                         (test_c_we),
     .test_c_dec                        (test_c_dec),
     .test_c_inc                        (test_c_inc),
     .test_d_clear                      (test_d_clear),
     .test_d_set                        (test_d_set),
     .test_e_clear                      (test_e_clear),
     .test_f_inc                        (test_f_inc),
     .test_f_clear                      (test_f_clear),
     .tick                              (tick));

  //---------------------------------------------------------------------

endmodule // testbench_001

// Local Variables:
// verilog-library-directories:("." "..")
// verilog-library-extensions:(".v")
// End:

